//
//  TXCNetMananger.swift
//  Demo
//
//  Created by ryan on 2021/8/13.
//

import Foundation
import Alamofire
import PromiseKit
import HandyJSON
import SwiftyJSON

/*
 Encodable 类型作为请求的参数。然后，这些参数通过遵循 ParameterEncoder 协议的类型传递，并添加到 URLRequest 中，然后通过网络发送。Alamofire 包含两种遵循 ParameterEncoder 的类型：JSONParameterEncoder 和 URLEncodedFormParameterEncoder 。这些类型涵盖了现代服务使用的最常见的编码。
 */
/// 请求参数和参数编码器
struct Login: Encodable {
    let account: String
    let password: String
}

//后台返回的数据格式
private let MSG = "msg"
private let DATA = "data"
private let CODE = "code"


/// 网络请求返回数据类型
private enum ResultDataType: Int {
    case array
    case model
    case json
}


public class TXCNetMananger: NSObject {
    
    public typealias TokenInvalidClosure = () -> ()
    private var configer: TXCNetConfiger = .init(environment: .develop)
    ///token失效的闭包
    private var tokenInvalidClosure: TokenInvalidClosure?
    private var netReachabilityMgr: NetworkReachabilityManager? = .init(host: "www.baidu.com")
    private var logDelegate: TXCNetLogProtocol?
    public static var shard: TXCNetMananger = .init()
    private override init() {
        super.init()
        AF.sessionConfiguration.timeoutIntervalForRequest = 20
        logDelegate = TXCNetLog.init()
        netReachabilityMgr?.startListening(onUpdatePerforming: { status in
            print("当前网络:", status)
            switch status {
            case .reachable(.ethernetOrWiFi):  //WIFI
                break
            case .notReachable: // 无网络
                break
            case .unknown:
                break
            case .reachable(.cellular): // 蜂窝网络
                break
            }
        })

    }
    /// 请求头
    var headers: HTTPHeaders {
        return [
            "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
            "Accept": "application/json"
        ]
    }
    
    //MARK:- 公开方法
    /// 设置 token 失效的 闭包
    public func setupTokenInvalid(handler: @escaping TokenInvalidClosure) {
        tokenInvalidClosure = handler
    }
    /// get 请求 model
    /// - Parameters:
    ///   - modelClass:  泛型
    ///   - path: 路径
    ///   - paramter: 参数
    /// - Returns: Promise<T>
    public func txc_get<T: HandyJSON>(path: String, paramter: [String: Any]) -> Promise<T> {
        return _requsetData(method: .get, path: path, paramter: paramter)
    }
    
    /// - Returns: Promise<T>
    public func txc_get2<T: HandyJSON>( path: String, paramter: [String: Any]) -> Promise<Array<T?>> {
        return _requsetData2(method: .get, path: path, paramter: paramter)
    }
    
    
    /// get 请求 JSON
    /// - Parameters:
    ///   - path: 路径
    ///   - paramter: 参数
    /// - Returns: 返回 Promise<JSON>
    public func txc_get(path: String, paramter: [String: Any]) -> Promise<JSON> {
        return _requsetData(method: .get, path: path, paramter: paramter)
    }
    
    /// post 请求 model
    /// - Parameters:
    ///   - modelClass: 泛型
    ///   - path: 路径
    ///   - paramter: 参数
    /// - Returns: Promise<T>
    public func txc_post<T: HandyJSON>(path: String, paramter: [String: Any]) -> Promise<T> {
        return _requsetData(method: .post, path: path, paramter: paramter)
    }
    
    public func txc_post2<T: HandyJSON>(path: String, paramter: [String: Any]) -> Promise<Array<T?>> {
        return _requsetData2(method: .post, path: path, paramter: paramter)
    }
    
    /// post 请求 JSON
    /// - Parameters:
    ///   - path: 路径
    ///   - paramter: 参数
    /// - Returns: 返回 Promise<[String: Any]>
    public func txc_post(path: String, paramter: [String: Any]) -> Promise<JSON> {
        return _requsetData(method: .post, path: path, paramter: paramter)
    }
    
    /// 上传一张图片
    /// - Parameters:
    ///   - image: 图片
    ///   - fileName: 名称
    /// - Returns: Promise<String> 图片ID
    public func txc_uploadImage(image: UIImage, fileName: String) -> Promise<String> {
        let jpegImage = image.jpegData(compressionQuality: 0.6)
        return _uploadImage(imageData: jpegImage!, fileName: fileName)
        
    }
    
    
    public func txc_uploadImages(images: [UIImage], fileName: String) -> Promise<[String]> {
        return Promise<[String]> { resolver in
            resolver.reject(TXCNetError(code: -222, msg: "暂未处理"))
        }
    }

    
    public func txc_test<T>(type: T.Type) {
        if type is Array<Any>.Type {
            print("array")
        }
        
        if type is [String: Any].Type {
            print("dic")
        }
        print("xxxx")
        
    }
    
    //MARK:- 私有方法
    /// 最底层的请求
    private func _requestData(path: String, method: HTTPMethod = .post, paramter: [String: Any], completion: @escaping (JSON?, TXCNetError?) -> Void ) {
        
        let url = configer.environment.domainStr + path
        logDelegate?.requetBefore(path: path, parameter: paramter)
        AF.request(url, method: method, parameters: paramter, headers: headers, interceptor: nil).validate()
            .responseJSON { response in
                self.logDelegate?.requetAfter(path: path, response: response.response, resultData: response.data)
                switch response.result {
                case let .success(str):
                    let json = JSON(str)
                    switch json[CODE].intValue {
                    case 1:
                        completion(json, nil)
                    case -1:
                        self._handlerTokenInvalid()
                        fallthrough
                    default:
                        completion(nil, TXCNetError(code: response.response?.statusCode, msg: json[MSG].stringValue))
                    }
                    
                case let .failure(err):
                    let code = response.response?.statusCode  // err.responseCode
                    //let msg = HTTPURLResponse.localizedString(forStatusCode: response.response!.statusCode)
                    completion(nil, TXCNetError(code: code, msg: err.localizedDescription))
            }
        }
    }

    /// 返回model HandyJSON 泛型
    private func _requsetData<T: HandyJSON>(method: HTTPMethod = .post, path: String, paramter: [String: Any]) -> Promise<T> {
        return Promise<T> { resolver in
            self._requestData(path: path, method: method, paramter: paramter) { (json, err) in
                
                if let error = err {
                    resolver.reject(error)
                } else if let json = json {
                    if let resultModel = T.deserialize(from: json.rawString(), designatedPath: "data.list") {
                        resolver.fulfill(resultModel)
                    } else {
                        resolver.reject(TXCNetError(code: json[CODE].int, msg: json[MSG].string ?? "数据解析失败"))
                    }
                } else {
                    resolver.reject(TXCNetError(code: -33, msg: "未知问题"))
                }

            }
        }
    }
    
    private func _requsetData2<T: HandyJSON>(method: HTTPMethod = .post, path: String, paramter: [String: Any]) -> Promise<Array<T?>> {
        return Promise<Array<T?>> { resolver in
            self._requestData(path: path, method: method, paramter: paramter) { (json, err) in
                
                if let error = err {
                    resolver.reject(error)
                } else if let json = json {
                    if let resultModel = [T].deserialize(from: json.rawString(), designatedPath: "data.list") {
                        resolver.fulfill(resultModel)
                    } else {
                        resolver.reject(TXCNetError(code: json[CODE].int, msg: json[MSG].string ?? "数据解析失败"))
                    }
                } else {
                    resolver.reject(TXCNetError(code: -33, msg: "未知问题"))
                }

            }
        }
    }
    /// 返回model JSON
    private func _requsetData(method: HTTPMethod = .post, path: String, paramter: [String: Any]) -> Promise<JSON> {
        
        return Promise<JSON> { resolver in
            self._requestData(path: path, method: method, paramter: paramter) { (json, err) in
                
                if let error = err {
                    resolver.reject(error)
                } else if let json = json {
                    resolver.fulfill(json)
                } else {
                    resolver.reject(TXCNetError(code: nil, msg: "数据解析失败"))
                }
                
            }
        }
        
    }
    /// 上传图片
    private func _uploadImage(imageData: Data, fileName: String) -> Promise<String> {
        let url = configer.environment.domainStr + "upload/"
        return Promise<String> { resolver in
            AF.upload(multipartFormData: { formData in
                formData.append(imageData, withName: "img", fileName:  fileName + ".jpeg", mimeType: "image/jpeg")
            }, to: url, usingThreshold: 1, method: .post, headers: headers).responseJSON { response in
                switch response.result {
                case let .success(str):
                    let json = JSON(str)
                    if let picId = json[DATA].string {
                        resolver.fulfill(picId)
                    } else {
                        resolver.reject(TXCNetError(code: -222, msg: json[MSG].string ?? "未知问题"))
                    }
                case let .failure(err):
                    resolver.reject(TXCNetError(code: err.responseCode, msg: err.localizedDescription))
                }
            }
        }
        
    }
    
    /// 暂时没有考虑好
    private func _resultCallBack<T>(type: ResultDataType, result: JSON?, err: TXCNetError?, dataType: T.Type) {

    }

    /// 处理token失效
    private func _handlerTokenInvalid()  {
        tokenInvalidClosure?()
    }
    

}


